window: handle tiled edges separately
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Thu, 17 Aug 2017 03:30:31 +0000 (00:30 -0300)
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Mon, 18 Sep 2017 02:16:48 +0000 (23:16 -0300)
GTK windows don't have their tiling states really
hooked into the client-side decoration code, and
the only effect it has is disabling the resizing
edges.

With the introduction of per-edge tiling information,
we are backed by much more precise data on how the
window manager wants the app to behave.

This patch, then, fixes GtkWindow to take into account
per-edge tiling information. For compatibility purposes,
the previous tiled field was kept, and thing will just
continue working if no edge information is supplied.

https://bugzilla.gnome.org/show_bug.cgi?id=783669

gtk/gtkwindow.c

index 2e8f5b4567072d85d972d679c464520f1d8aff00..d2af718414e056ddde7721af4a49de617a86efed 100644 (file)
@@ -215,6 +215,7 @@ struct _GtkWindowPrivate
   GtkWidget *popup_menu;
 
   gint       initial_fullscreen_monitor;
+  guint      edge_constraints;
 
   /* The following flags are initially TRUE (before a window is mapped).
    * They cause us to compute a configure request that involves
@@ -1702,11 +1703,13 @@ edge_under_coordinates (GtkWindow     *window,
   if (priv->type != GTK_WINDOW_TOPLEVEL ||
       !priv->client_decorated ||
       !priv->resizable ||
-      priv->tiled ||
       priv->fullscreen ||
       priv->maximized)
     return FALSE;
 
+  if (priv->tiled && !priv->edge_constraints)
+    return FALSE;
+
   _gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
   context = _gtk_widget_get_style_context (GTK_WIDGET (window));
   gtk_style_context_save_to_node (context, priv->decoration_node);
@@ -1740,6 +1743,9 @@ edge_under_coordinates (GtkWindow     *window,
           edge != GDK_WINDOW_EDGE_WEST &&
           edge != GDK_WINDOW_EDGE_SOUTH_WEST)
         return FALSE;
+
+      if (!(priv->edge_constraints & GDK_WINDOW_STATE_LEFT_RESIZABLE))
+        return FALSE;
     }
   else if (x >= allocation.x + allocation.width - border.right - handle_h)
     {
@@ -1747,6 +1753,9 @@ edge_under_coordinates (GtkWindow     *window,
           edge != GDK_WINDOW_EDGE_EAST &&
           edge != GDK_WINDOW_EDGE_SOUTH_EAST)
         return FALSE;
+
+      if (!(priv->edge_constraints & GDK_WINDOW_STATE_RIGHT_RESIZABLE))
+        return FALSE;
     }
   else if (edge != GDK_WINDOW_EDGE_NORTH &&
            edge != GDK_WINDOW_EDGE_SOUTH)
@@ -1759,6 +1768,9 @@ edge_under_coordinates (GtkWindow     *window,
           edge != GDK_WINDOW_EDGE_NORTH &&
           edge != GDK_WINDOW_EDGE_NORTH_EAST)
         return FALSE;
+
+      if (!(priv->edge_constraints & GDK_WINDOW_STATE_TOP_RESIZABLE))
+        return FALSE;
     }
   else if (y > allocation.y + allocation.height - border.bottom - handle_v)
     {
@@ -1766,6 +1778,9 @@ edge_under_coordinates (GtkWindow     *window,
           edge != GDK_WINDOW_EDGE_SOUTH &&
           edge != GDK_WINDOW_EDGE_SOUTH_EAST)
         return FALSE;
+
+      if (!(priv->edge_constraints & GDK_WINDOW_STATE_BOTTOM_RESIZABLE))
+        return FALSE;
     }
   else if (edge != GDK_WINDOW_EDGE_WEST &&
            edge != GDK_WINDOW_EDGE_EAST)
@@ -7132,6 +7147,25 @@ gtk_window_configure_event (GtkWidget         *widget,
   return TRUE;
 }
 
+static void
+update_edge_constraints (GtkWindow           *window,
+                         GdkEventWindowState *event)
+{
+  GtkWindowPrivate *priv = window->priv;
+  GdkWindowState state = event->new_window_state;
+
+  priv->edge_constraints = (state & GDK_WINDOW_STATE_TOP_TILED) |
+                           (state & GDK_WINDOW_STATE_TOP_RESIZABLE) |
+                           (state & GDK_WINDOW_STATE_RIGHT_TILED) |
+                           (state & GDK_WINDOW_STATE_RIGHT_RESIZABLE) |
+                           (state & GDK_WINDOW_STATE_BOTTOM_TILED) |
+                           (state & GDK_WINDOW_STATE_BOTTOM_RESIZABLE) |
+                           (state & GDK_WINDOW_STATE_LEFT_TILED) |
+                           (state & GDK_WINDOW_STATE_LEFT_RESIZABLE);
+
+  priv->tiled = (state & GDK_WINDOW_STATE_TILED) ? 1 : 0;
+}
+
 static gboolean
 gtk_window_state_event (GtkWidget           *widget,
                         GdkEventWindowState *event)
@@ -7148,12 +7182,6 @@ gtk_window_state_event (GtkWidget           *widget,
         (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) ? 1 : 0;
     }
 
-  if (event->changed_mask & GDK_WINDOW_STATE_TILED)
-    {
-      priv->tiled =
-        (event->new_window_state & GDK_WINDOW_STATE_TILED) ? 1 : 0;
-    }
-
   if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
     {
       priv->maximized =
@@ -7161,6 +7189,8 @@ gtk_window_state_event (GtkWidget           *widget,
       g_object_notify_by_pspec (G_OBJECT (widget), window_props[PROP_IS_MAXIMIZED]);
     }
 
+  update_edge_constraints (window, event);
+
   if (event->changed_mask & (GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_TILED))
     {
       update_window_style_classes (window);